package org.freeocs.entity;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.dbutils.DbUtils;
import org.freeocs.commons.cache.CacheHelper;
import org.freeocs.commons.db.QueryHelper;
import org.freeocs.commons.exception.DBException;
import org.freeocs.commons.search.SearchEnabled;
import org.freeocs.commons.util.Inflector;

/**
 * 持久化对象的基类
 * 
 * @author chirs
 */
public abstract class Pojo implements Serializable {
	private static final long serialVersionUID = -8445610789566903277L;
	public final static transient byte STATUS_PENDING = 0x00;
	public final static transient byte STATUS_NORMAL = 0x01;
	private final static transient char OBJ_COUNT_CACHE_KEY = '#';

	private long ___key_id;

	public long getId() {
		return ___key_id;
	}

	public void setId(long id) {
		this.___key_id = id;
	}

	private String __this_table_name;

	/**
	 * 返回默认的对象对应的表名
	 * 
	 * @return
	 */
	protected String TableName() {
		if (__this_table_name == null)
			__this_table_name = "freeocs_" + Inflector.getInstance().tableize(getClass());
		return __this_table_name;
	}

	/**
	 * 返回对象对应的缓存区域名
	 * 
	 * @return
	 */
	protected String CacheRegion() {
		return this.getClass().getSimpleName();
	}

	/**
	 * 是否根据ID缓存对象，此方法对Get(long id)有效
	 * 
	 * @return
	 */
	protected boolean IsObjectCachedByID() {
		return false;
	}

	/**
	 * 分页列出所有对象
	 * 
	 * @param page
	 * @param size
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List List(int page, int size) {
		String sql = "SELECT * FROM " + TableName() + " ORDER BY id DESC";
		return QueryHelper.query_slice(getClass(), sql, page, size);
	}

	protected int getView_count() {
		return 0;
	}

	protected void setView_count(int view_count) {
	}

	protected int getReply_count() {
		return 0;
	}

	protected void setReply_count(int reply_count) {
	}

	/**
	 * 更新浏览数
	 * 
	 * @param id
	 * @param count
	 * @return
	 */
	public boolean UpdateViewCount(long id, int count) {
		boolean ok = QueryHelper.update("UPDATE " + TableName() + " SET view_count=view_count+? WHERE id=?", count, id) == 1;
		if (ok) {
			Pojo obj = CacheHelper.get(getClass(), CacheRegion(), id);
			if (obj != null) {
				obj.setView_count(obj.getView_count() + count);
				CacheHelper.set(CacheRegion(), id, obj);
			}
		}
		return ok;
	}

	/**
	 * 更新评论数
	 * 
	 * @param id
	 * @param count
	 * @return
	 */
	protected boolean UpdateReplyCount(long id, int count) {
		boolean ok = QueryHelper.update("UPDATE " + TableName() + " SET reply_count=? WHERE id=?", count, id) == 1;
		if (ok) {
			Pojo obj = CacheHelper.get(getClass(), CacheRegion(), id);
			if (obj != null) {
				obj.setReply_count(count);
				CacheHelper.set(CacheRegion(), id, obj);
			}
		}
		return ok;
	}

	/**
	 * 插入对象到数据库表中
	 * 
	 * @return
	 */
	public long Save() {
		if (getId() > 0)
			_InsertObject(this);
		else
			setId(_InsertObject(this));
		if (this.IsObjectCachedByID())
			CacheHelper.evict(CacheRegion(), OBJ_COUNT_CACHE_KEY);
		return getId();
	}

	/**
	 * 根据id主键删除对象
	 * 
	 * @return
	 */
	public boolean Delete() {
		boolean dr = Evict(QueryHelper.update("DELETE FROM " + TableName() + " WHERE id=?", getId()) == 1);
		if (dr)
			CacheHelper.evict(CacheRegion(), OBJ_COUNT_CACHE_KEY);
		return dr;
	}

	/**
	 * 根据条件决定是否清除对象缓存
	 * 
	 * @param er
	 * @return
	 */
	protected boolean Evict(boolean er) {
		if (er && IsObjectCachedByID())
			CacheHelper.evict(CacheRegion(), getId());
		return er;
	}

	/**
	 * 清除指定主键的对象缓存
	 * 
	 * @param obj_id
	 */
	protected void Evict(long obj_id) {
		CacheHelper.evict(CacheRegion(), obj_id);
	}

	public Pojo Get(java.math.BigInteger id) {
		if (id == null)
			return null;
		return Get(id.longValue());
	}

	/**
	 * 根据主键读取对象详细资料，根据预设方法自动判别是否需要缓存
	 * 
	 * @param id
	 * @return
	 */
	public Pojo Get(long id) {
		if (id <= 0)
			return null;
		boolean cached = IsObjectCachedByID();
		Pojo obj = cached ? CacheHelper.get(getClass(), CacheRegion(), id) : null;
		if (obj == null) {
			obj = QueryHelper.read(getClass(), "SELECT * FROM " + TableName() + " WHERE id=?", id);
			if (obj != null && cached)
				CacheHelper.set(CacheRegion(), id, obj);
		}
		return obj;
	}

	/**
	 * 统计此对象的总记录数
	 * 
	 * @return
	 */
	public int TotalCount() {
		if (this.IsObjectCachedByID())
			return (int) QueryHelper.stat_cache(CacheRegion(), OBJ_COUNT_CACHE_KEY, "SELECT COUNT(*) FROM " + TableName());
		return (int) QueryHelper.stat("SELECT COUNT(*) FROM " + TableName());
	}

	@SuppressWarnings("unchecked")
	public List<SearchEnabled> ListAfter(long id, int count) {
		String sql = "SELECT * FROM " + TableName() + " WHERE id>? ORDER BY id LIMIT ?";
		return (List) QueryHelper.query(getClass(), sql, id, (count > 0) ? count : Integer.MAX_VALUE);
	}

	/**
	 * 返回索引存储的字段
	 * 
	 * @see org.freeocs.commons.search.SearchEnabled#GetStoreFields()
	 * @return
	 */
	public String[] GetStoreFields() {
		return null;
	}

	public HashMap<String, String> GetExtendValues() {
		return null;
	}

	/**
	 * @see org.freeocs.commons.search.SearchEnabled#GetBoost()
	 * @return
	 */
	public float GetBoost() {
		return 1;
	}

	/**
	 * 插入对象
	 * 
	 * @param obj
	 * @return 返回插入对象的主键
	 */

	private static long _InsertObject(Pojo obj) {
		Map<String, Object> pojo_bean = obj.ListInsertableFields();
		String[] fields = pojo_bean.keySet().toArray(new String[pojo_bean.size()]);
		StringBuilder sql = new StringBuilder("INSERT INTO ");
		sql.append(obj.TableName());
		sql.append('(');
		for (int i = 0; i < fields.length; i++) {
			if (i > 0)
				sql.append(',');
			sql.append(fields[i]);
		}
		sql.append(") VALUES(");
		for (int i = 0; i < fields.length; i++) {
			if (i > 0)
				sql.append(',');
			sql.append('?');
		}
		sql.append(')');
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			ps = QueryHelper.getConnection().prepareStatement(sql.toString(), PreparedStatement.RETURN_GENERATED_KEYS);
			for (int i = 0; i < fields.length; i++) {
				ps.setObject(i + 1, pojo_bean.get(fields[i]));
			}
			ps.executeUpdate();
			rs = ps.getGeneratedKeys();
			return rs.next() ? rs.getLong(1) : -1;
		} catch (SQLException e) {
			throw new DBException(e);
		} finally {
			DbUtils.closeQuietly(rs);
			DbUtils.closeQuietly(ps);
			sql = null;
			fields = null;
			pojo_bean = null;
		}
	}

	/**
	 * 列出要插入到数据库的域集合，子类可以覆盖此方法
	 * 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected Map<String, Object> ListInsertableFields() {
		try {
			Map<String, Object> props = BeanUtils.describe(this);
			if (getId() <= 0)
				props.remove("id");
			props.remove("class");
			return props;
		} catch (Exception e) {
			throw new RuntimeException("Exception when Fetching fields of " + this);
		}
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null)
			return false;
		if (obj == this)
			return true;
		// 不同的子类尽管ID是相同也是不相等的
		if (!getClass().equals(obj.getClass()))
			return false;
		Pojo wb = (Pojo) obj;
		return wb.getId() == getId();
	}

}